﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
//using System.Runtime.Serialization.Json;
using System.Windows.Forms;
using Newtonsoft.Json;

namespace WindowsCodeUnion
{
    public partial class Form1 : Form
    {
        // 配置/状态文件位置（应用数据）
        private static readonly string AppFolder = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            "FileCombinerTool");
        private static readonly string HistoryFile = Path.Combine(AppFolder, "history.json");

        // 扫描到的文件信息列表
        private List<FileItem> scannedFiles = new List<FileItem>();

        // 当前选择的 root folder
        private string currentRootFolder = null;

        // 默认的可识别文本扩展名集（可扩展）
        private static readonly string[] DefaultTextExtensions = new[]
        {
            ".cs", ".vb", ".cpp", ".c", ".h", ".js", ".ts", ".py", ".java", ".xml", ".xaml",
            ".json", ".txt", ".md", ".log", ".csv", ".css", ".html", ".htm", ".sql", ".bat",
            ".ps1", ".ini", ".config", ".properties"
        };

        // 存储历史路径（最近文件夹）
        private List<string> recentFolders = new List<string>();

        // 自定义目标文件夹
        private string customTargetFolder = null;

        // 上次生成的文件路径
        private string lastGeneratedFilePath = null;

        public Form1()
        {
            InitializeComponent();
            LoadHistory();
            checkBoxIncludeSubdirs.Checked = true;
            checkBoxAutoFileName.Checked = true;
            textBoxTargetFileName.Enabled = false;
            radioButtonDesktop.Checked = true;

            // 绑定 ListView 复选事件（在 ListView 中勾选不触发专门事件，使用 ItemChecked）
            listViewFiles.ItemChecked += ListViewFiles_ItemChecked;
        }

        #region 数据模型
        private class FileItem
        {
            public string FullPath { get; set; }
            public string RelativePath { get; set; }
            public string Extension { get; set; }
            public string Name => Path.GetFileName(FullPath);
        }

        //[DataContract]
        private class HistoryData
        {
            //[DataMember]
            public List<string> RecentFolders { get; set; } = new List<string>();
        }
        #endregion

        #region 历史路径 操作
        // LoadHistory 替换
        private void LoadHistory()
        {
            try
            {
                if (!Directory.Exists(AppFolder)) Directory.CreateDirectory(AppFolder);
                if (File.Exists(HistoryFile))
                {
                    var text = File.ReadAllText(HistoryFile, Encoding.UTF8);
                    var data = JsonConvert.DeserializeObject<HistoryData>(text);
                    if (data != null && data.RecentFolders != null)
                        recentFolders = data.RecentFolders.Where(d => Directory.Exists(d)).Distinct().ToList();
                }
            }
            catch
            {
                // ignore
            }
            RefreshHistoryCombo();
        }

        // SaveHistory 替换
        private void SaveHistory()
        {
            try
            {
                var data = new HistoryData { RecentFolders = recentFolders.Distinct().ToList() };
                var text = JsonConvert.SerializeObject(data, Formatting.Indented);
                File.WriteAllText(HistoryFile, text, Encoding.UTF8);
            }
            catch
            {
                // ignore
            }
        }

        private void RefreshHistoryCombo()
        {
            comboBoxHistory.Items.Clear();
            foreach (var d in recentFolders)
            {
                comboBoxHistory.Items.Add(d);
            }
        }

        private void AddToHistory(string folder)
        {
            if (string.IsNullOrWhiteSpace(folder)) return;
            recentFolders.RemoveAll(x => string.Equals(x, folder, StringComparison.OrdinalIgnoreCase));
            recentFolders.Insert(0, folder);
            if (recentFolders.Count > 30) recentFolders = recentFolders.Take(30).ToList();
            SaveHistory();
            RefreshHistoryCombo();
        }
        #endregion

        #region 打开/加载 文件夹
        private void buttonOpenFolder_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(currentRootFolder) && Directory.Exists(currentRootFolder))
            {
                folderBrowserDialog1.SelectedPath = currentRootFolder;
            }

            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                LoadFolder(folderBrowserDialog1.SelectedPath);
            }
        }

        private void buttonLoadHistory_Click(object sender, EventArgs e)
        {
            var sel = comboBoxHistory.SelectedItem as string;
            if (!string.IsNullOrEmpty(sel) && Directory.Exists(sel))
            {
                LoadFolder(sel);
            }
            else
            {
                MessageBox.Show("请选择有效的历史路径并加载。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void LoadFolder(string folder)
        {
            try
            {
                if (!Directory.Exists(folder))
                {
                    MessageBox.Show("指定文件夹不存在。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                currentRootFolder = folder;
                AddToHistory(folder);
                labelStatus.Text = $"加载中：{folder} ...";

                bool includeSub = checkBoxIncludeSubdirs.Checked;
                var extsSet = new HashSet<string>(DefaultTextExtensions, StringComparer.OrdinalIgnoreCase);

                var files = Directory.EnumerateFiles(folder, "*.*", includeSub ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                    .Where(f => extsSet.Contains(Path.GetExtension(f)))
                    .OrderBy(f => f, StringComparer.OrdinalIgnoreCase)
                    .ToList();

                scannedFiles.Clear();
                foreach (var f in files)
                {
                    scannedFiles.Add(new FileItem
                    {
                        FullPath = f,
                        RelativePath = MakeRelativePath(folder, f),
                        Extension = Path.GetExtension(f).ToLowerInvariant()
                    });
                }

                PopulateListView();
                BuildFileTypeCheckboxes();

                labelStatus.Text = $"已加载 {scannedFiles.Count} 个文件（包含子目录：{includeSub}）";
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载文件夹时出错：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                labelStatus.Text = "就绪";
            }
        }

        private static string MakeRelativePath(string baseDir, string fullPath)
        {
            try
            {
                var baseUri = new Uri(AddTrailingSlash(Path.GetFullPath(baseDir)));
                var fullUri = new Uri(Path.GetFullPath(fullPath));
                var rel = Uri.UnescapeDataString(baseUri.MakeRelativeUri(fullUri).ToString().Replace('/', Path.DirectorySeparatorChar));
                return rel;
            }
            catch
            {
                return fullPath;
            }
        }

        private static string AddTrailingSlash(string path)
        {
            if (!path.EndsWith(Path.DirectorySeparatorChar.ToString()))
                return path + Path.DirectorySeparatorChar;
            return path;
        }

        private void PopulateListView()
        {
            listViewFiles.BeginUpdate();
            listViewFiles.Items.Clear();
            foreach (var fi in scannedFiles)
            {
                var li = new ListViewItem(fi.Name) { Tag = fi };
                li.SubItems.Add(fi.RelativePath);
                li.Checked = true; // 默认勾选
                listViewFiles.Items.Add(li);
            }
            listViewFiles.EndUpdate();
        }

        private void BuildFileTypeCheckboxes()
        {
            groupBoxFileTypes.Controls.Clear();
            var groups = scannedFiles.Select(f => f.Extension).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(s => s).ToList();
            if (!groups.Any())
            {
                var lbl = new Label { Text = "未检测到支持的文本文件类型", AutoSize = true, Location = new System.Drawing.Point(10, 20) };
                groupBoxFileTypes.Controls.Add(lbl);
                return;
            }

            int x = 10, y = 20;
            foreach (var ext in groups)
            {
                var cb = new CheckBox
                {
                    Text = ext,
                    Tag = ext,
                    Checked = true,
                    AutoSize = true,
                    Location = new System.Drawing.Point(x, y)
                };
                cb.CheckedChanged += FileTypeCheckBox_CheckedChanged;
                groupBoxFileTypes.Controls.Add(cb);

                y += 24;
                if (y > groupBoxFileTypes.Height - 30)
                {
                    y = 20;
                    x += 120;
                }
            }
        }

        private void FileTypeCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            var cb = sender as CheckBox;
            if (cb == null) return;
            var ext = cb.Tag as string;
            if (string.IsNullOrEmpty(ext)) return;

            bool isChecked = cb.Checked;

            // 同步 listView 中对应类型的项勾选状态
            for (int i = 0; i < listViewFiles.Items.Count; i++)
            {
                var li = listViewFiles.Items[i];
                var fi = li.Tag as FileItem;
                if (fi != null && string.Equals(fi.Extension, ext, StringComparison.OrdinalIgnoreCase))
                {
                    li.Checked = isChecked;
                }
            }
        }

        private void ListViewFiles_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            // 如果你需要在单项勾选时做其他处理，可在此加入逻辑
        }
        #endregion

        #region 列表 操作（全选/全不选/排序）
        private void buttonSelectAll_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem li in listViewFiles.Items)
                li.Checked = true;
        }

        private void buttonSelectNone_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem li in listViewFiles.Items)
                li.Checked = false;
        }

        // ListView 按列排序（简单切换升降序）
        private int sortColumn = -1;
        private bool sortAscending = true;
        private void listViewFiles_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == sortColumn)
                sortAscending = !sortAscending;
            else
            {
                sortColumn = e.Column;
                sortAscending = true;
            }

            listViewFiles.ListViewItemSorter = new ListViewItemComparer(e.Column, sortAscending);
            listViewFiles.Sort();
        }

        private class ListViewItemComparer : System.Collections.IComparer
        {
            private int col;
            private bool asc;
            public ListViewItemComparer(int column, bool ascending)
            {
                col = column;
                asc = ascending;
            }

            public int Compare(object x, object y)
            {
                var a = x as ListViewItem;
                var b = y as ListViewItem;
                if (a == null || b == null) return 0;
                var res = string.Compare(a.SubItems[col].Text, b.SubItems[col].Text, StringComparison.OrdinalIgnoreCase);
                return asc ? res : -res;
            }
        }
        #endregion

        #region 目标文件夹 选择逻辑
        private void buttonSelectTargetFolder_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(customTargetFolder) && Directory.Exists(customTargetFolder))
            {
                folderBrowserDialog1.SelectedPath = customTargetFolder;
            }
            else if (!string.IsNullOrWhiteSpace(currentRootFolder) && Directory.Exists(currentRootFolder))
            {
                folderBrowserDialog1.SelectedPath = currentRootFolder;
            }

            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                customTargetFolder = folderBrowserDialog1.SelectedPath;
                radioButtonCustomFolder.Checked = true;
                labelStatus.Text = $"选择目标文件夹：{customTargetFolder}";
            }
        }

        private void buttonSelectDesktop_Click(object sender, EventArgs e)
        {
            radioButtonDesktop.Checked = true;
            labelStatus.Text = "目标位置：桌面";
        }

        private void buttonSelectCurrentFolder_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(currentRootFolder) || !Directory.Exists(currentRootFolder))
            {
                MessageBox.Show("当前未加载任何文件夹，无法选择被组合文件的文件夹。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            radioButtonCurrentFolder.Checked = true;
            labelStatus.Text = $"目标位置：{currentRootFolder}";
        }
        #endregion

        #region 自动文件名 逻辑
        private void checkBoxAutoFileName_CheckedChanged(object sender, EventArgs e)
        {
            textBoxTargetFileName.Enabled = !checkBoxAutoFileName.Checked;
        }

        private string GetTargetFolderForSave()
        {
            if (radioButtonDesktop.Checked)
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            }
            else if (radioButtonCurrentFolder.Checked)
            {
                // 使用当前 root folder（若为空，回退到桌面）
                if (!string.IsNullOrWhiteSpace(currentRootFolder) && Directory.Exists(currentRootFolder))
                    return currentRootFolder;
                else
                    return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            }
            else // custom
            {
                if (!string.IsNullOrWhiteSpace(customTargetFolder) && Directory.Exists(customTargetFolder))
                    return customTargetFolder;
                else
                {
                    MessageBox.Show("未设置自定义目标文件夹或该文件夹不存在，已回退到桌面。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                }
            }
        }

        private string GenerateAutoFileName()
        {
            return $"Combined_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
        }
        #endregion

        #region 生成合并 文件
        private void buttonGenerate_Click(object sender, EventArgs e)
        {
            try
            {
                var checkedItems = listViewFiles.CheckedItems;
                if (checkedItems.Count == 0)
                {
                    MessageBox.Show("请先选择要合并的文件。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                var selectedFiles = new List<FileItem>();
                foreach (ListViewItem li in checkedItems)
                {
                    if (li.Tag is FileItem fi) selectedFiles.Add(fi);
                }

                if (!selectedFiles.Any())
                {
                    MessageBox.Show("没有有效的文件被选中。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                var targetFolder = GetTargetFolderForSave();
                var fileName = checkBoxAutoFileName.Checked ? GenerateAutoFileName() : textBoxTargetFileName.Text.Trim();
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    MessageBox.Show("请提供目标文件名或勾选自动生成。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
                if (!fileName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
                    fileName += ".txt";

                if (!Directory.Exists(targetFolder))
                    Directory.CreateDirectory(targetFolder);

                var targetPath = Path.Combine(targetFolder, fileName);

                if (File.Exists(targetPath))
                {
                    var dr = MessageBox.Show($"目标文件已存在：{targetPath}\n是否覆盖？", "确认覆盖", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (dr != DialogResult.Yes)
                    {
                        labelStatus.Text = "已取消生成。";
                        return;
                    }
                }

                labelStatus.Text = $"开始合并到：{targetPath}";
                var utf8NoBom = new UTF8Encoding(false);

                using (var fs = new FileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.None))
                using (var sw = new StreamWriter(fs, utf8NoBom))
                {
                    var ordered = selectedFiles.OrderBy(f => f.RelativePath, StringComparer.OrdinalIgnoreCase).ToList();
                    for (int i = 0; i < ordered.Count; i++)
                    {
                        var fi = ordered[i];
                        sw.WriteLine($"----- 文件: {fi.RelativePath} -----");
                        try
                        {
                            using (var sr = new StreamReader(fi.FullPath, Encoding.UTF8, detectEncodingFromByteOrderMarks: true))
                            {
                                string content = sr.ReadToEnd();
                                sw.Write(content);
                            }
                        }
                        catch (Exception exFile)
                        {
                            sw.WriteLine($"[无法读取文件：{fi.FullPath}，错误：{exFile.Message}]");
                        }

                        if (i < ordered.Count - 1)
                            sw.WriteLine();
                    }
                }

                lastGeneratedFilePath = targetPath;
                labelStatus.Text = $"完成：{targetPath}";
                MessageBox.Show($"合并完成：{targetPath}", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"合并时出现错误：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                labelStatus.Text = "错误";
            }
        }

        private void buttonOpenOutputFile_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(lastGeneratedFilePath) && System.IO.File.Exists(lastGeneratedFilePath))
            {
                try
                {
                    System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{lastGeneratedFilePath}\"");
                }
                catch
                {
                    try
                    {
                        System.Diagnostics.Process.Start(lastGeneratedFilePath);
                    }
                    catch
                    {
                        MessageBox.Show("无法打开生成的文件。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
            else
            {
                MessageBox.Show("尚无可打开的生成文件，请先生成。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        #endregion
    }
}